home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-11-10 | 35.4 KB | 1,408 lines | [TEXT/PJMM] |
- unit WEHighLevelEditing;
-
- { WASTE PROJECT: }
- { High-Level Editing Routines }
-
- { Copyright © 1993-1994 Marco Piovanelli }
- { All Rights Reserved }
-
- interface
- uses
- WELowLevelEditing;
-
- const
-
- { action kinds }
-
- weAKNone = 0; { null action }
- weAKUnspecified = 1; { action of unspecified nature }
- weAKTyping = 2; { some text has been typed in }
- weAKCut = 3; { the selection range has been cut }
- weAKPaste = 4; { something has been pasted }
- weAKClear = 5; { the selection range has been deleted }
- weAKDrag = 6; { drag and drop operation }
- weAKSetStyle = 7; { some style has been applied to a text range }
-
- { action flags }
-
- weAFIsRedo = $0001; { action saves edit state prior to a WEUndo call }
- weAFDontSaveText = $0002; { don't save text }
- weAFDontSaveStyles = $0004; { don't save styles }
- weAFDontSaveSoup = $0008; { don't save embedded object information }
-
- type
-
- WEActionKind = Integer;
- WEActionFlags = Integer;
-
- { a WEAction record is used to record a single editing operation on a WE instance, }
- { like typing some text, cutting or pasting. A linked list of WEAction records might }
- { be used to implement multiple undo. }
-
- WEActionHandle = ^WEActionPtr;
- WEActionPtr = ^WEAction;
- WEAction = record
- hOwner: WEHandle; { handle to associated WE instance }
- hNext: WEActionHandle; { used to keep a linked list of actions }
- hText: Handle; { handle to saved text }
- hStyles: Handle; { handle to saved styles }
- hSoup: Handle; { handle to saved "soup" }
- delRangeStart: LongInt; { start of range to delete }
- delRangeLength: LongInt; { length of range to delete }
- insRangeLength: LongInt; { length of range to insert }
- hiliteStart: LongInt; { start of range to hilite }
- hiliteEnd: LongInt; { end of range to hilite }
- actionKind: WEActionKind; { identifies event that caused this action to be pushed }
- actionFlags: WEActionFlags; { miscellaneous flags }
- end; { WEAction }
-
- { high-level editing functions }
-
- procedure WEKey (key: Char;
- modifiers: Integer;
- hWE: WEHandle);
- function WEInsert (textPtr: Ptr;
- textLength: LongInt;
- hStyles: StScrpHandle;
- hSoup: Handle;
- hWE: WEHandle): OSErr;
- function WEInsertObject (objectType: OSType;
- objectDataHandle: Handle;
- objectSize: Point;
- hWE: WEHandle): OSErr;
- function WEDelete (hWE: WEHandle): OSErr;
- function WECut (hWE: WEHandle): OSErr;
- function WEPaste (hWE: WEHandle): OSErr;
- function WESetStyle (mode: Integer;
- var ts: WETextStyle;
- hWE: WEHandle): OSErr;
- function WEUseStyleScrap (hStyles: StScrpHandle;
- hWE: WEHandle): OSErr;
-
- { high-level Undo functions }
-
- function WEUndo (hWE: WEHandle): OSErr;
- procedure WEClearUndo (hWE: WEHandle);
- function WEGetUndoInfo (var redoFlag: Boolean;
- hWE: WEHandle): WEActionKind;
-
- { keeping track of changes }
-
- function WEGetModCount (hWE: WEHandle): LongInt;
- procedure WEResetModCount (hWE: WEHandle);
-
- { actions }
-
- function WENewAction (rangeStart, rangeEnd: LongInt;
- newTextLength: LongInt;
- actionKind: WEActionKind;
- actionFlags: WEActionFlags;
- hWE: WEHandle;
- var hAction: WEActionHandle): OSErr;
- procedure WEDisposeAction (hAction: WEActionHandle);
- function WEDoAction (hAction: WEActionHandle): OSErr;
-
- { low-level routines for directly manipulating }
- { the action stack associated with a given WE instance }
-
- function WEGetActionStack (hWE: WEHandle): WEActionHandle;
- function WEPushAction (hAction: WEActionHandle): OSErr;
-
- { miscellaneous }
-
- function WECanPaste: Boolean;
- procedure _WEAdjustUndoRange (moreBytes: LongInt;
- hWE: WEHandle);
- function WEIsTyping (hWE: WEHandle): Boolean;
-
- implementation
- uses
- WEScraps;
-
- function WEGetActionStack (hWE: WEHandle): WEActionHandle;
- begin
- WEGetActionStack := WEActionHandle(hWE^^.hActionStack);
- end; { WEGetActionStack }
-
- function WEPushAction (hAction: WEActionHandle): OSErr;
- var
- pWE: WEPtr;
- hLast: WEActionHandle;
- begin
- WEPushAction := noErr;
-
- { find the last action in the given stack }
- hLast := hAction;
- while (hLast^^.hNext <> nil) do
- hLast := hLast^^.hNext;
-
- { prepend hAction in front of the action stack }
- pWE := hAction^^.hOwner^;
- hLast^^.hNext := WEActionHandle(pWE^.hActionStack);
- pWE^.hActionStack := Handle(hAction);
-
- end; { WEPushAction }
-
- function WENewAction (rangeStart, rangeEnd: LongInt;
- newTextLength: LongInt;
- actionKind: WEActionKind;
- actionFlags: WEActionFlags;
- hWE: WEHandle;
- var hAction: WEActionHandle): OSErr;
- label
- 0, 1;
- var
- pAction: WEActionPtr;
- err: OSErr;
- begin
-
- { allocate a new action record }
- err := _WEAllocate(SizeOf(WEAction), kAllocClear, hAction);
- if (err <> noErr) then
- goto 1;
-
- { lock it down }
- HLock(Handle(hAction));
- pAction := hAction^;
-
- { fill in the fields }
- pAction^.hOwner := hWE;
- pAction^.delRangeStart := rangeStart;
- pAction^.delRangeLength := newTextLength;
- pAction^.insRangeLength := rangeEnd - rangeStart;
- pAction^.actionKind := actionKind;
- pAction^.actionFlags := actionFlags;
-
- { remember selection range }
- WEGetSelection(pAction^.hiliteStart, pAction^.hiliteEnd, hWE);
-
- { allocate a handle to hold the text to be saved, unless otherwise specified }
- if (BitAnd(actionFlags, weAFDontSaveText) = 0) then
- begin
- err := _WEAllocate(0, kAllocTemp, pAction^.hText);
- if (err <> noErr) then
- goto 1;
- end;
-
- { allocate a handle to hold the styles to be saved, unless otherwise specified }
- if (BitAnd(actionFlags, weAFDontSaveStyles) = 0) then
- begin
- err := _WEAllocate(0, kAllocTemp, pAction^.hStyles);
- if (err <> noErr) then
- goto 1;
- end;
-
- { allocate a handle to hold the "soup" to be saved, unless otherwise specified }
- if (BitAnd(actionFlags, weAFDontSaveSoup) = 0) then
- begin
- err := _WEAllocate(0, kAllocTemp, pAction^.hSoup);
- if (err <> noErr) then
- goto 1;
- end;
-
- { make a copy of text range }
- err := WECopyRange(rangeStart, rangeEnd, pAction^.hText, pAction^.hStyles, pAction^.hSoup, hWE);
- if (err <> noErr) then
- goto 1;
-
- { unlock action record }
- HUnlock(Handle(hAction));
-
- { skip clean-up section }
- goto 0;
-
- 1:
- { clean up }
- _WEForgetHandle(pAction^.hText);
- _WEForgetHandle(pAction^.hStyles);
- _WEForgetHandle(pAction^.hSoup);
- _WEForgetHandle(hAction);
-
- 0:
- { return result code }
- WENewAction := err;
-
- end; { WENewAction }
-
- procedure WEDisposeAction (hAction: WEActionHandle);
- var
- pAction: WEActionPtr;
- hNext: WEActionHandle;
- begin
- while (hAction <> nil) do
- begin
-
- { lock the action record }
- HLock(Handle(hAction));
- pAction := hAction^;
- hNext := pAction^.hNext;
-
- { throw away text, styles and soup }
- _WEForgetHandle(pAction^.hText);
- _WEForgetHandle(pAction^.hStyles);
- _WEForgetHandle(pAction^.hSoup);
-
- { throw away the action record itself }
- DisposeHandle(Handle(hAction));
-
- { repeat the same sequence with all linked actions }
- hAction := hNext;
-
- end; { while }
- end; { WEDisposeAction }
-
- procedure WEForgetAction (var hAction: WEActionHandle);
- var
- theAction: WEActionHandle;
- begin
- theAction := hAction;
- if (theAction <> nil) then
- begin
- hAction := nil;
- WEDisposeAction(theAction);
- end;
- end; { WEForgetAction }
-
- function WEDoAction (hAction: WEActionHandle): OSErr;
- label
- 1;
- var
- hRedoAction: WEActionHandle;
- pAction: WEActionPtr;
- hWE: WEHandle;
- pWE: WEPtr;
- offset, delOffset, insOffset: LongInt;
- redrawStart, redrawEnd: LongInt;
- saveActionLock, saveWELock, saveTextLock: Boolean;
- err: OSErr;
- begin
-
- { sanity check: make sure hAction isn't NIL }
- if (hAction = nil) then
- begin
- WEDoAction := nilHandleErr;
- Exit(WEDoAction);
- end;
-
- { get handle to associated WE instance }
- hWE := hAction^^.hOwner;
-
- { lock the WE record }
- saveWELock := _WESetHandleLock(hWE, true);
- pWE := hWE^;
-
- { hide selection highlighting and the caret }
- _WEHiliteRange(pWE^.selStart, pWE^.selEnd, hWE);
- if BTST(pWE^.flags, weFCaretVisible) then
- _WEBlinkCaret(hWE);
-
- redrawStart := maxLongInt;
- redrawEnd := 0;
-
- repeat
-
- { lock the action record }
- saveActionLock := _WESetHandleLock(hAction, true);
- pAction := hAction^;
- offset := pAction^.delRangeStart;
- delOffset := offset + pAction^.delRangeLength;
- insOffset := offset + pAction^.insRangeLength;
-
- { if undo support is enabled, save the range to be affected by this action }
- if (BTST(pWE^.flags, weFUndoSupport)) then
- if (WENewAction(offset, delOffset, pAction^.insRangeLength, pAction^.actionKind, BitXor(pAction^.actionFlags, weAFIsRedo), hWE, hRedoAction) = noErr) then
- if (WEPushAction(hRedoAction) <> noErr) then
- ;
-
- if (pAction^.hText <> nil) then
- begin
-
- { delete the range to replace }
- err := _WEDeleteRange(offset, delOffset, hWE);
- if (err <> noErr) then
- goto 1;
-
- { insert the saved text }
- saveTextLock := _WESetHandleLock(pAction^.hText, true);
- err := _WEInsertText(offset, pAction^.hText^, pAction^.insRangeLength, hWE);
- IgnoreBoolean(_WESetHandleLock(pAction^.hText, saveTextLock));
- if (err <> noErr) then
- goto 1;
-
- end;
-
- { apply the saved styles, if any }
- if (pAction^.hStyles <> nil) then
- begin
- err := _WEApplyStyleScrap(offset, insOffset, StScrpHandle(pAction^.hStyles), hWE);
- if (err <> noErr) then
- goto 1;
- end;
-
- { the same goes for the soup }
- if (pAction^.hSoup <> nil) then
- begin
- err := _WEApplySoup(offset, pAction^.hSoup, hWE);
- if (err <> noErr) then
- goto 1;
- end;
-
- { adjust redraw range }
- if (offset < redrawStart) then
- redrawStart := offset;
- if (insOffset > redrawEnd) then
- redrawEnd := insOffset;
-
- { unlock action record }
- IgnoreBoolean(_WESetHandleLock(hAction, saveActionLock));
-
- { go to next action }
- hAction := hAction^^.hNext;
-
- until (hAction = nil);
-
- { restore the original selection range }
- pWE^.selStart := pAction^.hiliteStart;
- pWE^.selEnd := pAction^.hiliteEnd;
-
- { redraw the text }
- err := _WERedraw(redrawStart, redrawEnd, hWE);
- if (err <> noErr) then
- goto 1;
-
- { clear result code }
- err := noErr;
-
- 1:
- { unlock the WE record }
- IgnoreBoolean(_WESetHandleLock(hWE, saveWELock));
-
- { return result code }
- WEDoAction := err;
-
- end; { WEDoAction }
-
- function WEUndo (hWE: WEHandle): OSErr;
- var
- pWE: WEPtr;
- hAction: WEActionHandle;
- saveWELock: Boolean;
- begin
-
- { lock the WE record }
- saveWELock := _WESetHandleLock(hWE, true);
- pWE := hWE^;
-
- { stop any ongoing inline input session }
- WEStopInlineSession(hWE);
-
- { "detach" the action stack from the WE instance }
- hAction := WEActionHandle(pWE^.hActionStack);
- pWE^.hActionStack := nil;
-
- if (hAction <> nil) then
- begin
-
- { undoing a change _decrements_ the modification count; }
- { redoing the change increments it again }
- if (BitAnd(hAction^^.actionFlags, weAFIsRedo) <> 0) then
- pWE^.modCount := pWE^.modCount + 1
- else
- pWE^.modCount := pWE^.modCount - 1;
-
- { perform the action... }
- WEUndo := WEDoAction(hAction);
-
- { ...and throw it away }
- WEDisposeAction(hAction);
-
- end
- else
-
- { return an error code if the undo buffer is empty }
- WEUndo := weCantUndoErr;
-
- { unlock the WE record }
- IgnoreBoolean(_WESetHandleLock(hWE, saveWELock));
-
- end; { WEUndo }
-
- procedure WEClearUndo (hWE: WEHandle);
- begin
-
- { dispose of the action chain associated with the given WE instance }
- WEForgetAction(WEActionHandle(hWE^^.hActionStack));
-
- end; { WEClearUndo }
-
- function WEGetUndoInfo (var redoFlag: Boolean;
- hWE: WEHandle): WEActionKind;
- begin
- WEGetUndoInfo := weAKNone; { assume no actions have been saved }
- redoFlag := false;
-
- if (hWE^^.hActionStack <> nil) then
- with WEActionHandle(hWE^^.hActionStack)^^ do
- begin
- WEGetUndoInfo := actionKind;
- redoFlag := (BitAnd(actionFlags, weAFIsRedo) <> 0);
- end;
- end; { WEGetUndoInfo }
-
- function WEGetModCount (hWE: WEHandle): LongInt;
- begin
- WEGetModCount := hWE^^.modCount;
- end; { WEGetModCount }
-
- procedure WEResetModCount (hWE: WEHandle);
- begin
- hWE^^.modCount := 0;
- WEClearUndo(hWE);
- end; { WEResetModCount }
-
- procedure _WEAdjustUndoRange (moreBytes: LongInt;
- hWE: WEHandle);
- var
- hAction: WEActionHandle;
- begin
- hAction := WEActionHandle(hWE^^.hActionStack);
- if (hAction <> nil) then
- with hAction^^ do
- delRangeLength := delRangeLength + moreBytes;
- end; { _WEAdjustUndoRange }
-
- function _WETypeChar (theByte: SignedByte;
- hWE: WEHandle): OSErr;
- label
- 0, 1;
- var
- pWE: WEPtr;
- db: DoubleByte;
- offset, endOffset, charLength: LongInt;
- byteType: Integer;
- saveFont: Integer;
- savePort: GrafPtr;
- err: OSErr;
- begin
- pWE := hWE^; { the WE record must be already locked }
- charLength := 1; { assume 1-byte character by default }
- db.firstByte := theByte;
- offset := pWE^.selStart;
-
- { delete current selection, if any }
- err := _WEDeleteRange(offset, pWE^.selEnd, hWE);
- if (err <> noErr) then
- goto 1;
- (*pWE^.selEnd := offset;*)
-
- { make sure the font script is synchronized with the keyboard script }
- _WESynchNullStyle(hWE);
-
- if BTST(pWE^.flags, weFDoubleByte) then
- begin
-
- { special processing for double-byte characters }
- if (pWE^.firstByte <> 0) then
- begin
-
- { if this byte is the second half of a double-byte character, }
- { insert the two bytes at the same time (flush the double-byte cache) }
- db.firstByte := pWE^.firstByte;
- db.secondByte := theByte;
- charLength := 2;
- pWE^.firstByte := 0;
- end
- else
- begin
-
- { determine the byte-type of theByte; first set up the port and its font }
- GetPort(savePort);
- SetPort(pWE^.port);
- saveFont := pWE^.port^.txFont;
- TextFont(pWE^.nullStyle.runStyle.tsFont);
-
- { call CharByte }
- byteType := CharByte(@theByte, 0);
-
- { put back font and port }
- TextFont(saveFont);
- SetPort(savePort);
-
- { if theByte is the first half of a double-byte character, just cache it and exit }
- if (byteType = smFirstByte) then
- begin
- pWE^.firstByte := theByte;
- goto 0;
- end;
- end;
-
- end; { if double-byte script installed }
-
- { insert the new character into the text }
- err := _WEInsertText(offset, @db, charLength, hWE);
- if (err <> noErr) then
- goto 1;
-
- { adjust undo buffer for the new character }
- _WEAdjustUndoRange(charLength, hWE);
-
- { invalid the null style }
- BCLR(pWE^.flags, weFUseNullStyle);
-
- { move the insertion point after the new character }
- endOffset := offset + charLength;
- pWE^.selStart := endOffset;
- pWE^.selEnd := endOffset;
-
- { redraw the text }
- err := _WERedraw(offset, endOffset, hWE);
- if (err <> noErr) then
- goto 1;
-
- 0:
- { clear result code }
- err := noErr;
-
- 1:
- { return result code }
- _WETypeChar := err;
-
- end; { _WETypeChar }
-
- function _WEBackspace (hWE: WEHandle): OSErr;
-
- { this routine is called by WEKey to handle the backspace key }
- { the WE record is guaranteed to be already locked }
-
- label
- 0, 1;
- var
- pWE: WEPtr;
- pAction: WEActionPtr;
- rangeStart, rangeEnd, charLength: LongInt;
- pChars: WECharsPtr;
- runInfo: WERunInfo;
- saveActionLock: Boolean;
- err: OSErr;
- begin
- pWE := hWE^;
-
- { calculate the text range to delete }
- { if the selection is non-empty, delete that }
- rangeStart := pWE^.selStart;
- rangeEnd := pWE^.selEnd;
- if (rangeStart = rangeEnd) then
- begin
-
- { otherwise the selection is an insertion point }
- { do nothing if insertion point is at the beginning of the text }
- if (rangeStart = 0) then
- goto 0;
-
- { determine the byte-type of the character preceding the insertion point }
- if (WECharByte(rangeStart - 1, hWE) = smSingleByte) then
- charLength := 1
- else
- charLength := 2;
- rangeStart := rangeStart - charLength;
-
- if (pWE^.hActionStack <> nil) then
- begin
-
- { UNDO SUPPORT FOR BACKSPACES }
-
- { lock the action record }
- saveActionLock := _WESetHandleLock(pWE^.hActionStack, true);
- pAction := WEActionHandle(pWE^.hActionStack)^;
-
- { backspaces over the newly entered text aren't a problem }
- if (pAction^.delRangeLength > 0) then
- pAction^.delRangeLength := pAction^.delRangeLength - charLength
- else
- begin
-
- { the hard part comes when backspacing past the new text because }
- { the user is about to delete a character not included in the block we saved }
-
- { lengthen our saved text handle }
- err := %_SetHandleSize(pAction^.hText, pAction^.insRangeLength + charLength);
- if (err <> noErr) then
- goto 1;
-
- { move old contents forward }
- pChars := WECharsHandle(pAction^.hText)^;
- %_BlockMoveData(@pChars^[0], @pChars^[charLength], pAction^.insRangeLength);
-
- { prepend the character to be deleted to the beginning of our saved text handle }
- pChars^[0] := WEGetChar(rangeStart, hWE);
- if (charLength = 2) then
- pChars^[1] := WEGetChar(rangeStart + 1, hWE);
-
- { adjust internal counters }
- pAction^.insRangeLength := pAction^.insRangeLength + charLength;
- pAction^.delRangeStart := pAction^.delRangeStart - charLength;
-
- { get style run info associated with the about-to-be-deleted character }
- WEGetRunInfo(rangeStart, runInfo, hWE);
-
- { prepend a new style element to our style scrap, if necessary }
- err := _WEPrependStyle(pAction^.hStyles, runInfo, charLength);
- if (err <> noErr) then
- goto 1;
-
- { do the same with our object "soup" }
- err := _WEPrependObject(pAction^.hSoup, runInfo, charLength);
- if (err <> noErr) then
- goto 1;
-
- end; { if deleting old text }
-
- { unlock the action record }
- IgnoreBoolean(_WESetHandleLock(pWE^.hActionStack, saveActionLock));
-
- end; { if undo support is enabled }
- end; { if selection is empty }
-
- err := _WEDeleteRange(rangeStart, rangeEnd, hWE);
- if (err <> noErr) then
- goto 1;
-
- { keep track of current selection range }
- pWE^.selStart := rangeStart;
- pWE^.selEnd := rangeStart;
-
- { redraw the text }
- err := _WERedraw(rangeStart, rangeStart, hWE);
- if (err <> noErr) then
- goto 1;
-
- 0:
- { clear result code }
- err := noErr;
-
- 1:
- { return result code }
- _WEBackspace := err;
-
- end; { _WEBackspace }
-
- function _WEForwardDelete (hWE: WEHandle): OSErr;
-
- { this routine is called by WEKey to handle the forward delete key }
- { the WE record is guaranteed to be already locked }
-
- label
- 0, 1;
- var
- pWE: WEPtr;
- pAction: WEActionPtr;
- rangeStart, rangeEnd, charLength: LongInt;
- runInfo: WERunInfo;
- db: DoubleByte;
- saveActionLock: Boolean;
- err: OSErr;
- begin
- pWE := hWE^;
-
- { calculate the text range to delete }
- { if the selection is non-empty, delete that }
- rangeStart := pWE^.selStart;
- rangeEnd := pWE^.selEnd;
- if (rangeStart = rangeEnd) then
- begin
-
- { otherwise the selection is an insertion point }
- { do nothing if insertion point is at the end of the text }
- if (rangeStart = pWE^.textLength) then
- goto 0;
-
- { determine the byte-type of the character following the insertion point }
- if (WECharByte(rangeStart, hWE) = smSingleByte) then
- charLength := 1
- else
- charLength := 2;
- rangeEnd := rangeStart + charLength;
-
- if (pWE^.hActionStack <> nil) then
- begin
-
- { UNDO SUPPORT FOR FORWARD DELETE }
-
- { lock the action record }
- saveActionLock := _WESetHandleLock(pWE^.hActionStack, true);
- pAction := WEActionHandle(pWE^.hActionStack)^;
-
- { make a copy of the character about to be deleted }
- db.firstByte := SignedByte(WEGetChar(rangeStart, hWE));
- if (charLength = 2) then
- db.secondByte := SignedByte(WEGetChar(rangeStart + 1, hWE));
-
- { append it to the end of our saved text handle }
- err := %_PtrAndHand(@db, pAction^.hText, charLength);
- if (err <> noErr) then
- goto 1;
-
- { get style run info associated with the about-to-be-deleted character }
- WEGetRunInfo(rangeStart, runInfo, hWE);
-
- { append a new style element to our style scrap, if necessary }
- err := _WEAppendStyle(pAction^.hStyles, runInfo, pAction^.insRangeLength);
- if (err <> noErr) then
- goto 1;
-
- { do the same with our object soup }
- err := _WEAppendObject(pAction^.hSoup, runInfo, pAction^.insRangeLength);
- if (err <> noErr) then
- goto 1;
-
- { adjust internal counters }
- pAction^.insRangeLength := pAction^.insRangeLength + charLength;
-
- { unlock the action record }
- IgnoreBoolean(_WESetHandleLock(pWE^.hActionStack, saveActionLock));
-
- end; { if undo support is enabled }
- end; { if selection is empty }
-
- err := _WEDeleteRange(rangeStart, rangeEnd, hWE);
- if (err <> noErr) then
- goto 1;
-
- { keep track of current selection range }
- pWE^.selStart := rangeStart;
- pWE^.selEnd := rangeStart;
-
- { redraw the text }
- err := _WERedraw(rangeStart, rangeStart, hWE);
- if (err <> noErr) then
- goto 1;
-
- 0:
- { clear result code }
- err := noErr;
-
- 1:
- { return result code }
- _WEForwardDelete := err;
-
- end; { _WEForwardDelete }
-
- function WEIsTyping (hWE: WEHandle): Boolean;
- var
- pWE: WEPtr;
- begin
-
- { return TRUE if we're tracking a typing sequence in the specified WE instance }
-
- WEIsTyping := false; { assume we aren't }
- pWE := hWE^; { the WE record must already be locked }
-
- { there must be an undo buffer }
- if (pWE^.hActionStack = nil) then
- Exit(WEIsTyping);
-
- with WEActionHandle(pWE^.hActionStack)^^ do
- begin
-
- { the action kind must be "typing" and the redo flag must be clear }
- if (actionKind <> weAKTyping) then
- Exit(WEIsTyping);
- if (BitAnd(actionFlags, weAFIsRedo) <> 0) then
- Exit(WEIsTyping);
-
- { finally, the selection range mustn't have moved since the last WEKey }
- if ((pWE^.selStart = pWE^.selEnd) and (pWE^.selStart = delRangeStart + delRangeLength)) then
- WEIsTyping := true;
- end; { with }
- end; { WEIsTyping }
-
- procedure WEKey (key: Char;
- modifiers: Integer;
- hWE: WEHandle);
- var
- pWE: WEPtr;
- hAction: WEActionHandle;
- saveWELock: Boolean;
- begin
-
- { lock the WE record }
- saveWELock := _WESetHandleLock(hWE, true);
- pWE := hWE^;
-
- { hide the caret if it's showing }
- if BTST(pWE^.flags, weFCaretVisible) then
- _WEBlinkCaret(hWE);
-
- { hide the cursor (it will show again as soon as it's moved) }
- ObscureCursor;
-
- { dispatch on key class (arrow keys, printable characters, backspace) }
- if ((ORD(key) >= kArrowLeft) and (ORD(key) <= kArrowDown)) then
- _WEDoArrowKey(ORD(key), modifiers, hWE)
- else
- begin
-
- { are we tracking a typing sequence? }
- if (WEIsTyping(hWE) = false) then
- begin
-
- { nope; so start a new one }
- { increment modification count }
- pWE^.modCount := pWE^.modCount + 1;
-
- { if undo support is enabled, create a new action to keep track of the typing }
- if (BTST(pWE^.flags, weFUndoSupport)) then
- begin
- WEClearUndo(hWE);
- if (WENewAction(pWE^.selStart, pWE^.selEnd, 0, weAKTyping, 0, hWE, hAction) = noErr) then
- if (WEPushAction(hAction) <> noErr) then
- ;
- end;
- end;
-
- if (ORD(key) = kBackspace) then
- IgnoreShort(_WEBackspace(hWE))
- else if (ORD(key) = kForwardDelete) then
- IgnoreShort(_WEForwardDelete(hWE))
- else
- IgnoreShort(_WETypeChar(ORD(key), hWE));
- end;
-
- { unlock the WE record }
- IgnoreBoolean(_WESetHandleLock(hWE, saveWELock));
-
- end; { WEKey }
-
- function WEInsert (textPtr: Ptr;
- textLength: LongInt;
- hStyles: StScrpHandle;
- hSoup: Handle;
- hWE: WEHandle): OSErr;
- label
- 1;
- var
- pWE: WEPtr;
- offset, endOffset: LongInt;
- hAction: WEActionHandle;
- intPasteAction: Integer;
- saveWELock: Boolean;
- space: SignedByte;
- err: OSErr;
- begin
-
- { stop any ongoing inline input session }
- WEStopInlineSession(hWE);
-
- { lock the WE record }
- saveWELock := _WESetHandleLock(hWE, true);
- pWE := hWE^;
- offset := pWE^.selStart;
-
- { increment modification count }
- pWE^.modCount := pWE^.modCount + 1;
-
- { if undo support is enabled, save current selection range }
- if (BTST(pWE^.flags, weFUndoSupport)) then
- begin
- WEClearUndo(hWE);
- if (WENewAction(offset, pWE^.selEnd, textLength, weAKUnspecified, 0, hWE, hAction) = noErr) then
- if (WEPushAction(hAction) <> noErr) then
- ;
- end;
-
- { delete current selection }
- err := _WEDeleteRange(offset, pWE^.selEnd, hWE);
- if (err <> noErr) then
- goto 1;
-
- { insert the new text at the insertion point }
- err := _WEInsertText(offset, textPtr, textLength, hWE);
- if (err <> noErr) then
- goto 1;
- endOffset := offset + textLength;
-
- if (hStyles <> nil) then
- begin
-
- { if a style scrap was supplied, apply it to the newly inserted text }
- err := _WEApplyStyleScrap(offset, endOffset, hStyles, hWE);
- if (err <> noErr) then
- goto 1;
- end;
-
- if (hSoup <> nil) then
- begin
-
- { if an object soup was supplied, apply it to the newly inserted text }
- err := _WEApplySoup(offset, hSoup, hWE);
- if (err <> noErr) then
- goto 1;
- end;
-
- { determine whether an extra space should be added before or after the inserted text }
- intPasteAction := _WEIntelligentPaste(offset, endOffset, hWE);
-
- { add the extra space, if necessary }
- if (intPasteAction <> weDontAddSpaces) then
- begin
-
- space := 32;
- if (intPasteAction = weAddSpaceOnLeftSide) then
- err := _WEInsertText(offset, @space, 1, hWE)
- else
- err := _WEInsertText(endOffset, @space, 1, hWE);
- if (err <> noErr) then
- goto 1;
- endOffset := endOffset + 1;
-
- { adjust undo buffer (if any) for the extra space }
- _WEAdjustUndoRange(1, hWE);
-
- end;
-
- { invalid the null style }
- BCLR(pWE^.flags, weFUseNullStyle);
-
- { move the insertion point at the end of the inserted text }
- pWE^.selStart := endOffset;
- pWE^.selEnd := endOffset;
-
- { redraw the text }
- err := _WERedraw(offset, endOffset, hWE);
- if (err <> noErr) then
- goto 1;
-
- { clear result code }
- err := noErr;
-
- 1:
- { return result code }
- WEInsert := err;
-
- { unlock the WE record }
- IgnoreBoolean(_WESetHandleLock(hWE, saveWELock));
-
- end; { WEInsert }
-
- function WEInsertObject (objectType: OSType;
- objectDataHandle: Handle;
- objectSize: Point;
- hWE: WEHandle): OSErr;
- label
- 1;
- var
- pWE: WEPtr;
- hAction: WEActionHandle;
- offset, endOffset: LongInt;
- ts: WETextStyle;
- marker: SignedByte;
- saveWELock: Boolean;
- err: OSErr;
- begin
- _WEBlockClr(@ts, SizeOf(ts));
-
- { stop any ongoing inline input session }
- WEStopInlineSession(hWE);
-
- { lock the WE record }
- saveWELock := _WESetHandleLock(hWE, true);
- pWE := hWE^;
- offset := pWE^.selStart;
-
- { call the 'new' handler to initialize private object storage (if any) }
- { and to calculate the default size for this object }
- err := _WENewObject(objectType, objectDataHandle, hWE, WEObjectDescHandle(ts.tsObject));
- if (err <> noErr) then
- goto 1;
-
- { use the specified object size, unless it is (0, 0), in which case keep the default size }
- if (LongInt(objectSize) <> 0) then
- WEObjectDescHandle(ts.tsObject)^^.objectSize := objectSize;
-
- { increment modification count }
- pWE^.modCount := pWE^.modCount + 1;
-
- { if undo support is enabled, save current selection range }
- if (BTST(pWE^.flags, weFUndoSupport)) then
- begin
- WEClearUndo(hWE);
- if (WENewAction(offset, pWE^.selEnd, 1, weAKUnspecified, 0, hWE, hAction) = noErr) then
- if (WEPushAction(hAction) <> noErr) then
- ;
- end;
-
- { delete current selection }
- err := _WEDeleteRange(offset, pWE^.selEnd, hWE);
- if (err <> noErr) then
- goto 1;
-
- { insert a kObjectMarker character at the insertion point }
- marker := kObjectMarker;
- err := _WEInsertText(offset, @marker, 1, hWE);
- if (err <> noErr) then
- goto 1;
-
- { move the insertion point after the inserted text }
- endOffset := offset + 1;
- pWE^.selStart := endOffset;
- pWE^.selEnd := endOffset;
-
- { record a reference to the object descriptor in the style table }
- err := _WESetStyleRange(offset, endOffset, weDoObject, ts, hWE);
- ts.tsObject := kNullObject;
- if (err <> noErr) then
- goto 1;
-
- { invalid the null style }
- BCLR(pWE^.flags, weFUseNullStyle);
-
- { redraw the text }
- err := _WERedraw(offset, endOffset, hWE);
- if (err <> noErr) then
- goto 1;
-
- { clear result code }
- err := noErr;
-
- 1:
- { return result code }
- WEInsertObject := err;
-
- { clean up }
- _WEForgetHandle(ts.tsObject);
-
- { unlock the WE record }
- IgnoreBoolean(_WESetHandleLock(hWE, saveWELock));
-
- end; { WEInsertObject }
-
- function WEDelete (hWE: WEHandle): OSErr;
- label
- 1;
- var
- pWE: WEPtr;
- hAction: WEActionHandle;
- rangeStart, rangeEnd: LongInt;
- saveWELock: Boolean;
- err: OSErr;
- begin
-
- { stop any ongoing inline input session }
- WEStopInlineSession(hWE);
-
- { lock the WE record }
- saveWELock := _WESetHandleLock(hWE, true);
- pWE := hWE^;
-
- { get current selection range }
- rangeStart := pWE^.selStart;
- rangeEnd := pWE^.selEnd;
-
- { do nothing if the selection range is empty }
- if (rangeStart < rangeEnd) then
- begin
-
- { increment modification count }
- pWE^.modCount := pWE^.modCount + 1;
-
- { range extension for intelligent cut-and-paste }
- _WEIntelligentCut(rangeStart, rangeEnd, hWE);
-
- { if undo support is enabled, save the range to be deleted }
- if (BTST(pWE^.flags, weFUndoSupport)) then
- begin
- WEClearUndo(hWE);
- if (WENewAction(rangeStart, rangeEnd, 0, weAKClear, 0, hWE, hAction) = noErr) then
- if (WEPushAction(hAction) <> noErr) then
- ;
- end;
-
- { delete the selection range }
- err := _WEDeleteRange(rangeStart, rangeEnd, hWE);
- if (err <> noErr) then
- goto 1;
-
- { reset the selection range }
- pWE^.selStart := rangeStart;
- pWE^.selEnd := rangeStart;
-
- { redraw the text }
- err := _WERedraw(rangeStart, rangeStart, hWE);
- if (err <> noErr) then
- goto 1;
-
- end; { if non-empty selection }
-
- { clear result code }
- err := noErr;
-
- 1:
- { return result code }
- WEDelete := err;
-
- { unlock the WE record }
- IgnoreBoolean(_WESetHandleLock(hWE, saveWELock));
-
- end; { WEDelete }
-
- function WECut (hWE: WEHandle): OSErr;
- var
- err: OSErr;
- begin
- WECut := noErr;
-
- { Cut is just Copy + Delete }
- err := WECopy(hWE);
- if (err <> noErr) then
- begin
- WECut := err;
- Exit(WECut);
- end;
-
- err := WEDelete(hWE);
- if (err <> noErr) then
- begin
- WECut := err;
- Exit(WECut);
- end;
-
- { change the action kind of the most recent action, if any }
- if (hWE^^.hActionStack <> nil) then
- WEActionHandle(hWE^^.hActionStack)^^.actionKind := weAKCut;
-
- end; { WECut }
-
- function WECanPaste: Boolean;
- var
- scrapOffset: LongInt;
- objectType: OSType;
- index: Integer;
- begin
- WECanPaste := true; { assume success }
-
- { return TRUE if the desk scrap contains a text flavor }
- if (GetScrap(nil, kTypeText, scrapOffset) > 0) then
- Exit(WECanPaste);
-
- { see if the desk scrap contains a flavor matching one of the registered object types }
- index := 0;
- while (_WEGetIndObjectType(index, objectType) = noErr) do
- begin
- if (GetScrap(nil, objectType, scrapOffset) > 0) then
- Exit(WECanPaste);
- index := index + 1;
- end; { while }
-
- WECanPaste := false;
- end; { WECanPaste }
-
- function WEPaste (hWE: WEHandle): OSErr;
- label
- 1;
- var
- hItem: Handle;
- hStyles: Handle;
- hSoup: Handle;
- selStart: LongInt;
- scrapOffset: LongInt;
- objectType: OSType;
- objectSize: Point;
- index: Integer;
- err: OSErr;
- begin
- hItem := nil;
- hStyles := nil;
- hSoup := nil;
- selStart := hWE^^.selStart;
-
- { allocate a handle to hold a scrap item }
- err := _WEAllocate(0, kAllocTemp, hItem);
- if (err <> noErr) then
- goto 1;
-
- { look for a text flavor }
- if (GetScrap(hItem, kTypeText, scrapOffset) <= 0) then
- begin
-
- { no text: look for a flavor matching one of the registered object types }
- index := 0;
- while (_WEGetIndObjectType(index, objectType) = noErr) do
- begin
- if (GetScrap(hItem, objectType, scrapOffset) > 0) then
- begin
-
- { found a registered type: create a new object out of the tagged data }
- err := WEInsertObject(objectType, hItem, Point(0), hWE);
-
- { if successful, set hItem to NIL so clean-up section won't kill the object data }
- if (err = noErr) then
- hItem := nil;
- goto 1;
- end;
-
- { try with next flavor }
- index := index + 1;
- end; { while }
-
- { nothing pasteable: return an error code }
- err := noTypeErr;
- goto 1;
- end;
-
- { allocate a handle to hold the style scrap, if any }
- err := _WEAllocate(0, kAllocTemp, hStyles);
- if (err <> noErr) then
- goto 1;
-
- { look for a 'styl' item accompanying the text }
- if (GetScrap(hStyles, kTypeStyles, scrapOffset) <= 0) then
-
- { forget the handle if nothing was found or an error occurred }
- _WEForgetHandle(hStyles);
-
- { allocate a handle to hold the soup, if any }
- err := _WEAllocate(0, kAllocTemp, hSoup);
- if (err <> noErr) then
- goto 1;
-
- { look for a 'SOUP' item accompanying the text }
- if (GetScrap(hSoup, kTypeSoup, scrapOffset) <= 0) then
-
- { forget the handle if nothing was found or an error occurred }
- _WEForgetHandle(hSoup);
-
- { lock down the text }
- HLock(hItem);
-
- { insert the text }
- err := WEInsert(hItem^, %_GetHandleSize(hItem), StScrpHandle(hStyles), hSoup, hWE);
-
- 1:
- { if successful, change the action kind of the most recent action, if any }
- if (err = noErr) then
- if (hWE^^.hActionStack <> nil) then
- WEActionHandle(hWE^^.hActionStack)^^.actionKind := weAKPaste;
-
- { clean up }
- _WEForgetHandle(hItem);
- _WEForgetHandle(hStyles);
- _WEForgetHandle(hSoup);
-
- { return result code }
- WEPaste := err;
-
- end; { WEPaste }
-
- function WESetStyle (mode: Integer;
- var ts: WETextStyle;
- hWE: WEHandle): OSErr;
- label
- 1;
- var
- pWE: WEPtr;
- hAction: WEActionHandle;
- fontScript: ScriptCode;
- saveWELock: Boolean;
- err: OSErr;
- begin
-
- { stop any ongoing inline input session }
- WEStopInlineSession(hWE);
-
- { lock the WE record }
- saveWELock := _WESetHandleLock(hWE, true);
- pWE := hWE^;
-
- if (pWE^.selStart = pWE^.selEnd) then
- begin
-
- { NULL SELECTION }
- { first make sure the nullStyle field contains valid information }
- _WESynchNullStyle(hWE);
-
- { apply style changes to the nullStyle record }
- _WECopyStyle(ts, pWE^.nullStyle.runStyle, pWE^.nullStyle.runStyle.tsFace, mode);
-
- { if the font was altered, synchronize the keyboard script }
- if BTST(pWE^.flags, weFNonRoman) then
- if BTST(mode, kModeFont) then
- begin
- fontScript := Font2Script(pWE^.nullStyle.runStyle.tsFont);
- if (fontScript <> GetEnvirons(smKeyScript)) then
- KeyScript(fontScript);
- end;
-
- end
- else
- begin
-
- { NON-EMPTY SELECTION }
-
- { increment modification count }
- pWE^.modCount := pWE^.modCount + 1;
-
- { if undo support is enabled, save the styles of the text range to be affected }
- if (BTST(pWE^.flags, weFUndoSupport)) then
- begin
- WEClearUndo(hWE);
- if (WENewAction(pWE^.selStart, pWE^.selEnd, pWE^.selEnd - pWE^.selStart, weAKSetStyle, weAFDontSaveText + weAFDontSaveSoup, hWE, hAction) = noErr) then
- if (WEPushAction(hAction) <> noErr) then
- ;
- end;
-
- { set the style of the selection range }
- err := _WESetStyleRange(pWE^.selStart, pWE^.selEnd, mode, ts, hWE);
- if (err <> noErr) then
- goto 1;
-
- { and redraw the text }
- err := _WERedraw(pWE^.selStart, pWE^.selEnd, hWE);
- if (err <> noErr) then
- goto 1;
-
- end;
-
- { clear the result code }
- err := noErr;
-
- 1:
- { unlock the WE record }
- IgnoreBoolean(_WESetHandleLock(hWE, saveWELock));
-
- { return result code }
- WESetStyle := err;
-
- end; { WESetStyle }
-
- function WEUseStyleScrap (hStyles: StScrpHandle;
- hWE: WEHandle): OSErr;
- label
- 1;
- var
- pWE: WEPtr;
- saveWELock: Boolean;
- err: OSErr;
- begin
-
- { lock the WE record }
- saveWELock := _WESetHandleLock(hWE, true);
- pWE := hWE^;
-
- { apply the style scrap to the selection range }
- err := _WEApplyStyleScrap(pWE^.selStart, pWE^.selEnd, hStyles, hWE);
- if (err <> noErr) then
- goto 1;
-
- { redraw the text }
- err := _WERedraw(pWE^.selStart, pWE^.selEnd, hWE);
-
- 1:
- { return result code }
- WEUseStyleScrap := err;
-
- { unlock the WE record }
- IgnoreBoolean(_WESetHandleLock(hWE, saveWELock));
-
- end; { WEUseStyleScrap }
-
- end.